
// ===============================================================================================================
// -*- C++ -*-
//
// Image.hpp - Declaration of an image interface class, a TGA image loader and an image factory.
//
// Copyright (c) 2006-2007 David Henry
//
// This code is licenced under the MIT license.
//
// This software is provided "as is" without express or implied
// warranties. You may freely copy and compile this source into
// applications you distribute provided that the copyright text
// above is included in the resulting source code.
//
// Modified by: Guilherme R. Lampert - March 2011
// guilherme.ronaldo.lampert@gmail.com
//
// ===============================================================================================================

#ifndef __IMAGE_HPP__
#define __IMAGE_HPP__

// Local includes
#include <Common.hpp>
#include <RefPtr.hpp>
#include <ReferenceCountable.hpp>
#include <MemoryBuffer.hpp>

// ===============================================================================================================
// Image class diagram:
//
//     +------- (abs)                +-------------------- (abs)
//     |  Image  | ----------------> |  ReferenceCountable  |
//     +---------+                   +----------------------+
//         ^
//         |
//         |                         +----------------+ 
//         |                         |  ImageFactory  | ---> Image objects can only be created
//         |   +------------+        +----------------+      thru the ImageFactory.
//         +---|  ImageTGA  |
//             +------------+
//                                   +----------------+
//                                   |  MemoryBuffer  | ---> Image loading uses the MemoryBuffer class
//                                   +----------------+      internaly.
//
// ===============================================================================================================

///
/// Image -- A generic image class for creating textures from.
/// All other specific image loaders are derived from it.
///
/// The Image class is reference counted and cloneable.
///
class Image : public ReferenceCountable {

public:

	// Public Interface:

	/// Tests if the image dimensions form a power of two image.
	bool IsPowerOfTwo(void) const;

	/// Checks if the image creation succeded.
	bool Fail(void) const;

	/// Returns a clone of the image.
	Image * Clone(void) const;

	// Accessors:

	inline int Width(void)  const { return (width); }
	inline int Height(void) const { return (height); }

	inline int Format(void) const { return (format); }
	inline int Components(void) const { return (components); }
	inline int NumMipmaps(void) const { return (numMipmaps); }

	inline bool StdCoordSystem(void) const { return (standardCoordSystem); }
	inline const std::string & FileName(void) const { return (fileName); }

	/// Get a pointer the the image pixel buffer.
	/// Always call Release() on the return when done.
	inline MemoryBuffer * Pixels(void) const
	{
		pixels->AddRef();
		return (pixels);
	}

	// ReferenceCountable Methods:

	virtual unsigned long AddRef(void) const;
	virtual unsigned long Release(void) const;
	virtual unsigned long ReferenceCount(void) const;

protected:

	// This will prevent the class from being staticaly allocated.
	// The only way to create an instance of it now is thru the ImageFactory class.

	// Constructors:

	Image(void) // Construct an invalid image.
	: width(0), height(0), numMipmaps(0), format(0), components(0),
	pixels(0), standardCoordSystem(true), ReferenceCountable()
	{ /**/ }

	Image(const Image & rhs) // Construct from copy:
	: width(rhs.width), height(rhs.height), numMipmaps(rhs.numMipmaps), format(rhs.format), components(rhs.components),
	pixels(rhs.pixels->Clone()), fileName(rhs.fileName), standardCoordSystem(rhs.standardCoordSystem), ReferenceCountable()
	{ /**/ }

	virtual ~Image(void);

protected:

	// Member Variables:

	// Image size info:
	int width;
	int height;
	int numMipmaps;

	// Texture format and internal format (components):
	unsigned int format;
	int components;

	// Image data stored in a MemoryBuffer:
	MemoryBuffer * pixels;

	// File that originated the image.
	std::string fileName;

	// Is the picture in standard OpenGL 2D coordinate
	// system? (starts lower-left corner)
	bool standardCoordSystem;

private:

	// Disable asignment copy.
	Image & operator = (const Image &);
};

///
/// Reference countable image pointer type.
///
typedef RefPtr<Image> ImagePtr;

// ===============================================================================================================

///
/// ImageTGA -- A TrueVision TARGA (TGA) image loader class.
/// Support 24-32 bits BGR files; 16 bits RGB; 8 bits indexed (BGR palette);
/// 8 and 16 bits grayscale; all compressed and uncompressed.
/// Compressed TGA images use RLE algorithm.
///
class ImageTGA : public Image {

	/*
	 * Copyright (c) 2006-2007 David Henry
	 *
	 * Modified by: Guilherme R. Lampert - March 2011
	 */

public:

	// Constructors:

	// Construct from memory:
	ImageTGA(const MemoryBuffer * memory, const std::string & originalFile);

	// Construct from file:
	ImageTGA(const std::string & fileName);

private:

#pragma pack (push, 1)

	///
	/// TGA Image Header.
	///
	struct TGA_Header {

		GLubyte id_lenght;        ///< Size of image id
		GLubyte colormap_type;    ///< 1 is has a colormap
		GLubyte image_type;       ///< Compression type

		short cm_first_entry;     ///< Colormap origin
		short cm_length;          ///< Colormap length
		GLubyte cm_size;          ///< Colormap size

		short x_origin;           ///< Bottom left x coord origin
		short y_origin;           ///< Bottom left y coord origin

		short width;              ///< Picture width (in pixels)
		short height;             ///< Picture height (in pixels)

		GLubyte pixel_depth;      ///< Bits per pixel: 8, 16, 24 or 32
		GLubyte image_descriptor; ///< 24 bits = 0x00; 32 bits = 0x80
	};

#pragma pack (pop)

private:

	// Internal Methods:

	/// Extract OpenGL texture informations from a TGA header.
	void getTextureInfo(const TGA_Header * header);

	/// Do the actual work reading the image.
	bool readTGAData(const MemoryBuffer * memory, const std::string & originalFile);

	// Uncompressed images:
	void readTGA8bits(const GLubyte * data, const GLubyte * colormap);
	void readTGA16bits(const GLubyte * data);
	void readTGA24bits(const GLubyte * data);
	void readTGA32bits(const GLubyte * data);
	void readTGAgray8bits(const GLubyte * data);
	void readTGAgray16bits(const GLubyte * data);

	// RLE compressed images:
	void readTGA8bitsRLE(const GLubyte * data, const GLubyte * colormap);
	void readTGA16bitsRLE(const GLubyte * data);
	void readTGA24bitsRLE(const GLubyte * data);
	void readTGA32bitsRLE(const GLubyte * data);
	void readTGAgray8bitsRLE(const GLubyte * data);
	void readTGAgray16bitsRLE(const GLubyte * data);

private:

	// NOTE:
	// 16 bits images are stored in RGB
	// 8-24-32 images are stored in BGR(A)

	// RGBA/BGRA component table access -- usefull for switching from bgra to rgba at load time.
	static const int rgbaTable[4]; // bgra to rgba: 2, 1, 0, 3
	static const int bgraTable[4]; // bgra to bgra: 0, 1, 2, 3
};

// ===============================================================================================================

///
/// ImageFactory -- An image factory class.
///
/// This class is not instantiable, it has all its methods declared as static.
///
class ImageFactory {

public:

	// Public Interface:

	/// Loads an image from a file.
	static Image * CreateImageFromFile(const std::string & fileName);

	/// Create an image from a memory buffer containing the image data.
	/// It also expects a name (usualy the name of the file that originated the image)
	/// that is used to identify the image by some other classes, such as textures.
	static Image * CreateImageFromMemory(const MemoryBuffer * memory, const std::string & originalFile);

private:

	ImageFactory(void);
	ImageFactory & operator = (const ImageFactory &);
};

#endif // __IMAGE_HPP__